package com.wewins.fota.sys.service;

import com.alibaba.fastjson.JSON;
import com.wewins.fota.bean.bo.RedisLuaResp;
import com.wewins.fota.bean.bo.StatInfo;
import com.wewins.fota.common.constant.RedisConst;
import com.wewins.fota.sys.config.FotaManagementConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

import static com.wewins.fota.common.constant.RedisConst.*;

@Slf4j
@Service
public class StatisticService {
    private final RedisTemplate<String, String> template;

    private final FotaManagementConfig config;

    public StatisticService(RedisTemplate<String, String> template, FotaManagementConfig config) {
        this.template = template;
        this.config = config;
    }

    public void initService() {
        Runnable runnable = () -> {
            log.info("start to init fota statistic thread.");
            clearStatistic();
            statisticMonitor();
        };
        Thread thread = new Thread(runnable, "fota-statistic-by-redis");
        thread.start();
    }

    private void clearStatistic() {
        Set<String> keys = this.template.keys(RedisConst.REDIS_KEY_STATISTIC);
        if (keys != null && keys.size() > 0) {
            this.template.delete(keys);
        }
    }

    private void statisticMonitor() {
        while (true) {
            try {
                Thread.sleep(this.config.getStatisticTime().toMillis());
                String rst = template.execute(
                        RedisScript.of(this.config.getStatOperator(), String.class),
                        Arrays.asList(REDIS_CMD_STAT_GET, REDIS_KEY_STATISTIC)
                );
                RedisLuaResp resp = JSON.parseObject(rst, RedisLuaResp.class);
                if (resp == null) {
                    log.error("lua script execute exception, next try again!!");
                    continue;
                }
                printStat(resp.parseRstList(StatInfo.class));
            } catch (Exception e) {
                log.info("statistic error happen:", e);
                this.initService();
                break;
            }
        }
    }

    private void printStat(List<StatInfo> statInfos) {
        if (statInfos == null) {
            log.info("recently [" + this.config.getStatisticTime().toMinutes() + "] min not any monitor api is visited!!!");
            return;
        }
        statInfos.forEach(item -> log.info(item.withStatTimeRange(this.config.getStatisticTime()).toLog()));
    }

    public void stat(String typeName, String costTime) {
        String rst = template.execute(RedisScript.of(this.config.getStatOperator(), String.class),
                Arrays.asList(REDIS_CMD_STAT_UPDATE, REDIS_KEY_STATISTIC, typeName), costTime);
        if (StringUtils.isEmpty(rst)) {
            log.warn("failed to stat current req status, api: " + typeName + ", cost:" + costTime + " ms");
        }
    }
}
